package pikasial.graphique;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Observable;
import java.util.concurrent.Semaphore;

import javax.swing.BorderFactory;
import javax.swing.DefaultListCellRenderer;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JMenu;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JScrollPane;
import javax.swing.JToolBar;
import javax.swing.ListSelectionModel;
import javax.swing.ProgressMonitor;
import javax.swing.ScrollPaneConstants;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;

import pikasial.Pikasial;
import pikasial.fs.Dossier;
import pikasial.images.*;

/**
 * Représente un onglet dans le navigateur de photos.
 * <p>
 * Un onglet correspond à la vue d'un album, même l'onglet par défaut,
 * qui est la vue de l'album par défaut (album particulier).
 * Dans un onglet, les images de l'album sont affichées sous la forme
 * d'une liste de vignettes.</p>
 *
 * @author ESIAL - Groupe 14
 */
@SuppressWarnings("serial")
public final class ExplorateurVignettes extends JPanel
	implements java.util.Observer, ListSelectionListener {

	/* Gros composants de l'explorateur */
	private JScrollPane scrollPane;
	private JPanel panelSud;
    private JToolBar controles;
    private PanneauRechercheTri recherche;

    /** L'album observé. */
    private ImageContainer album;

    /** La liste des vignettes. */
    private JList list;

    private JPopupMenu popup;
    private JMenu ajoutAlbum;
    private JMenuItem delFromAlbum;
    private PhotosListModel plm;
    private ProgressMonitor progress;

    /* ****!!!!!!!! Nouveau !!!!!!!!**** */
    /* Le parallèlisme marche à peu près... j'en ai vraiment chié mais on
     * peut maintenant cliquer sur un autre album et annuler le précédent
     * chargement. Provoque un dead-lock sur les gros albums (thread de remplissage
     * des dossiers ??). Il vaut donc mieux cliquer sur annuler dans la progress
     * bar pour les gros dossiers, puis cliquer sur le nouveau à charger.
     */
    private boolean chargementEnCours;
    private Thread chargeur;
    private Semaphore semaphore;

    private JButton diaporama;
    private JButton fullScreen;
    private JButton affich;
    private JButton suppr;
    private JButton proprietes;
    private JButton ajoutComment;
    private JButton ajoutTag;
    private JMenuItem paste;

    private ImageIcon diaporamaIcon;
    private ImageIcon fullscreenIcon;
    private ImageIcon supprIcon;
    private ImageIcon tagsIcon;
    private ImageIcon commentIcon;
    private ImageIcon visionneuseIcon;
    private ImageIcon propertiesIcon;
    private ImageIcon cutIcon;
    private ImageIcon copyIcon;
    private ImageIcon pasteIcon;

    private BoiteCommentaire commentBox;
    private TagBox tagBox;


    /**
     * Crée un onglet observant l'album passé en paramètre.
     *
     * @param ap - l'album à observer
     */
    public ExplorateurVignettes() {
        super();
        ListeAlbums.getInstance().addObserver(this);
        chargementEnCours = false;
        semaphore = new Semaphore(1);
        diaporamaIcon = new ImageIcon(getClass().getResource(pikasial.utils.PikasialConstantes.SLIDESHOW_ICON_PATH));
        fullscreenIcon = new ImageIcon(getClass().getResource(pikasial.utils.PikasialConstantes.FULLSCREEN_ICON_PATH));
        supprIcon = new ImageIcon(getClass().getResource(pikasial.utils.PikasialConstantes.REMOVE_ICON_PATH));
        tagsIcon = new ImageIcon(getClass().getResource(pikasial.utils.PikasialConstantes.TAGS_ICON_PATH));
        commentIcon = new ImageIcon(getClass().getResource(pikasial.utils.PikasialConstantes.COMMENT_ICON_PATH));
        visionneuseIcon = new ImageIcon(getClass().getResource(pikasial.utils.PikasialConstantes.ALBUM_24_ICON_PATH));
        propertiesIcon = new ImageIcon(getClass().getResource(pikasial.utils.PikasialConstantes.PROPERTIES_ICON_PATH));
        cutIcon = new ImageIcon(getClass().getResource(pikasial.utils.PikasialConstantes.CUT_ICON_PATH));
        copyIcon = new ImageIcon(getClass().getResource(pikasial.utils.PikasialConstantes.COPY_ICON_PATH));
        pasteIcon = new ImageIcon(getClass().getResource(pikasial.utils.PikasialConstantes.PASTE_ICON_PATH));

        initComponents();
        initPopupMenu();
    }

    public ExplorateurVignettes(ImageContainer im) {
        this();
        ListeAlbums.getInstance().setAlbumAffiche(im);
    }

    private void initPopupMenu() {
        popup = new JPopupMenu();
        JMenuItem afficher = new JMenuItem("Afficher", 'f');
        afficher.setIcon(visionneuseIcon);
        afficher.addActionListener(new ActionListener() {

            public void actionPerformed(ActionEvent e) {
                PikImage p = (PikImage) list.getModel().
                    getElementAt(list.getSelectedIndex());
                VisionneuseImage.getInstance().afficherImage(p);
            }
        });

        delFromAlbum = new JMenuItem(" ", 's');
        delFromAlbum.setIcon(supprIcon);
        delFromAlbum.addActionListener(new ActionListener() {

            public void actionPerformed(ActionEvent e) {
                int rep = JOptionPane.showConfirmDialog(pikasial.Pikasial.getFrame(),
                    "Etes-vous sur de vouloir supprimer ces images?",
                    "Confirmation", JOptionPane.YES_NO_OPTION,
                    JOptionPane.QUESTION_MESSAGE);
                if (rep == JOptionPane.YES_OPTION) {
                    Object[] selection = list.getSelectedValues();
                    PikImage[] imgs = new PikImage[selection.length];
                    for (int i=0; i<selection.length; i++) {
                    	imgs[i] = (PikImage) selection[i];
                    }
                    supprimerImages(imgs);
                }
            }
        });

        ajoutAlbum = new JMenu("Ajouter à l'album");
        ajoutAlbum.setIcon(new ImageIcon(getClass().getResource(pikasial.utils.PikasialConstantes.ADD_ICON_PATH)));
        ajoutAlbum.setMnemonic('a');
        JMenuItem cut = new JMenuItem("Couper",cutIcon);
        cut.addActionListener(new ActionListener() {
        	public void actionPerformed(ActionEvent ae) {
        		PressePapier.getInstance().couper(getSelectedVignettes(),getAlbum());
        	}
        });
        JMenuItem copy = new JMenuItem("Copier",copyIcon);
        copy.addActionListener(new ActionListener() {
        	public void actionPerformed(ActionEvent ae) {
        		PressePapier.getInstance().copier(getSelectedVignettes());
        	}
        });
        paste = new JMenuItem("Coller",pasteIcon);
        paste.addActionListener(new ActionListener() {
        	public void actionPerformed(ActionEvent ae) {
        		PikImage[] imgs = PressePapier.getInstance().coller();
        		for (PikImage pik : imgs) {
        			album.addImage(pik);
        		}
        		plm.synchroniserAvecAlbum();
        	}
        });

        JMenuItem properties = new JMenuItem("Propriétés");
        properties.setIcon(propertiesIcon);
        properties.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                PikImage p = (PikImage) list.getModel().
                    getElementAt(list.getSelectedIndex());
                new ProprietesImageDialog(p);
            }
        });

        popup.add(afficher);
        popup.addSeparator();
        popup.add(ajoutAlbum);
        popup.add(delFromAlbum);
        popup.addSeparator();
        popup.add(cut);
        popup.add(copy);
        popup.add(paste);
        popup.addSeparator();
        popup.add(properties);
    }

    private void updatePopup() {
        delFromAlbum.setText("Supprimer " +
            ((album instanceof pikasial.fs.Dossier)
            ? "du dossier" : "de l'album"));
        paste.setEnabled(!PressePapier.getInstance().isEmpty());
        ajoutAlbum.removeAll();
        JMenuItem nouv = new JMenuItem("Nouvel album...",'n');
        nouv.setIcon(new ImageIcon(getClass().getResource(pikasial.utils.PikasialConstantes.ALBUM_NEW_ICON_PATH)));
        nouv.addActionListener(new ActionListener() {
        	public void actionPerformed(ActionEvent ae) {
        		String nomAlbum = (String) JOptionPane.showInputDialog(pikasial.Pikasial.getFrame(),
        				"Nom de l'album :", "Nouvel album",
        				JOptionPane.QUESTION_MESSAGE);
        		if (nomAlbum != null && nomAlbum.length() > 0) {
        			AlbumPhotos ap;
        			if (ListeAlbums.getInstance().containsAlbum(nomAlbum)) {
        				JOptionPane.showMessageDialog(pikasial.Pikasial.getFrame(),
        						"Ce nom est déjà utilisé !",
        						"Erreur",
        						JOptionPane.ERROR_MESSAGE);
        			} else {
        				ap = new AlbumPhotos(nomAlbum);
        				Object[] obj = list.getSelectedValues();
        				for (int i=0; i < obj.length; i++) {
        					ap.addImage((PikImage) obj[i]);
        				}
        				ListeAlbums.getInstance().ajouterAlbum(ap);
        				ListeAlbums.getInstance().setAlbumAffiche(ap);
        			}
        		}
        	}
        });
        //ajoutAlbum.add(nouv);

        boolean albumPresent = false;
        Collection<AlbumPhotos> collec = ListeAlbums.getInstance().getAllAlbums();
        for (final AlbumPhotos ap : collec) {
            JMenuItem item = new JMenuItem(ap.getName());
            item.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    Object[] selection = list.getSelectedValues();
                    ArrayList<PikImage> images = new ArrayList<PikImage>();
                    for (Object o : selection) {
                        images.add((PikImage) o);
                    }
                    ap.addAllImages(images);
                }
            });
            if (!ListeAlbums.getInstance().getAlbumAffiche().equals(ap)) {
                ajoutAlbum.add(item);
                albumPresent = true;
            }
        }

        if (albumPresent) { ajoutAlbum.addSeparator(); }
        ajoutAlbum.add(nouv);
    }

    private void initComponents() {
        scrollPane = new JScrollPane(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED,
            ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
        setLayout(new BorderLayout());
        recherche = new PanneauRechercheTri();
        list = new JList();
        recherche.setAlbumModel(null);
        list.getSelectionModel().addListSelectionListener(this);
        list.addMouseListener(new MouseAdapter() {

            public void mouseClicked(final MouseEvent arg0) {
                if (arg0.getButton() == MouseEvent.BUTTON1 &&
                    arg0.getClickCount() >= 2) {
                    int index = list.locationToIndex(arg0.getPoint());
                    if (index != -1) {
                    	PikImage p = (PikImage) list.getModel().getElementAt(index);
                    	VisionneuseImage.getInstance().afficherImage(p);
                    }
                }
            }
            public void mouseReleased(final MouseEvent arg0) {
                if (arg0.getButton() == MouseEvent.BUTTON3) {
                    int index = list.locationToIndex(arg0.getPoint());
                    if (index != -1) {
                    	if (list.isSelectionEmpty() || !list.isSelectedIndex(index)) {
                    		list.setSelectedIndex(index);
                    	}
                    	updatePopup();
                    	popup.show(arg0.getComponent(), arg0.getX(), arg0.getY());
                    }
                }
            }
        });

        list.setCellRenderer(new ImageRenderer());
        list.setLayoutOrientation(JList.HORIZONTAL_WRAP);
        list.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
        list.setVisibleRowCount(-1);

        panelSud = new JPanel();
        controles = new JToolBar();
        controles.setLayout(new FlowLayout(FlowLayout.CENTER, 10, 5));
        controles.setFloatable(false);
        diaporama = new JButton(diaporamaIcon);
        diaporama.setToolTipText("Diaporama");
        fullScreen = new JButton(fullscreenIcon);
        fullScreen.setToolTipText("Plein écran");
        affich = new JButton(visionneuseIcon);
        affich.setToolTipText("Afficher dans la visionneuse");
        suppr = new JButton(supprIcon);
        suppr.setToolTipText("Supprimer l'image");
        proprietes = new JButton(propertiesIcon);
        proprietes.setToolTipText("Afficher les propriétés de l'image");
        ajoutComment = new JButton(commentIcon);
        ajoutComment.setToolTipText("Editer le commentaire de l'image");
        ajoutTag = new JButton(tagsIcon);
        ajoutTag.setToolTipText("Editer les tags de l'image");
        fullScreen.setEnabled(false);
		proprietes.setEnabled(false);
		ajoutComment.setEnabled(false);
		affich.setEnabled(false);
		ajoutTag.setEnabled(false);
		suppr.setEnabled(false);
        suppr.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent arg0) {
                if (!list.isSelectionEmpty()) {
                    int rep = JOptionPane.showConfirmDialog(pikasial.Pikasial.getFrame(),
                        "Etes-vous sur de vouloir supprimer ces images de l'album ?", "Attention",
                        JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE);
                    if (rep == JOptionPane.YES_OPTION) {
                    	Object[] selection = list.getSelectedValues();
                    	PikImage[] imgs = new PikImage[selection.length];
                        for (int i=0; i<selection.length; i++) {
                        	imgs[i] = (PikImage) selection[i];
                        }
                        supprimerImages(imgs);
                    }
                }
            }
        });
        fullScreen.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
            	if (!list.isSelectionEmpty()) {
            		Diaporama d = new Diaporama(ExplorateurVignettes.this.getAlbum());
            		d.afficher();
            		d.afficherImage((PikImage) list.getSelectedValue());
            	}
            }
        });
        diaporama.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
            	if (!album.isEmpty()) {
            		Diaporama d = new Diaporama(ExplorateurVignettes.this.getAlbum());
            		d.afficher();
            		d.diaporama();
            	} else {
            		JOptionPane.showMessageDialog(Pikasial.getFrame(), "L'album est vide !",
            				"Erreur", JOptionPane.ERROR_MESSAGE);
            	}
            }
        });
        affich.addActionListener(new ActionListener() {

            public void actionPerformed(ActionEvent ae) {
                if (!list.isSelectionEmpty()) {
                    VisionneuseImage.getInstance().
                        afficherImage((PikImage) ExplorateurVignettes.this.list.getSelectedValue());
                }
            }
        });
        ajoutComment.addActionListener(new ActionListener() {

			public void actionPerformed(ActionEvent arg0) {
				if (tagBox != null)
					tagBox.close();
				if (!list.isSelectionEmpty()) {
					commentBox = new BoiteCommentaire((PikImage) list.getSelectedValue());
					SwingUtilities.invokeLater(new Runnable() {
						public void run() {
							panelSud.removeAll();
							panelSud.add(commentBox);
							panelSud.repaint();
							panelSud.validate();
							ExplorateurVignettes.this.validate();
						}
					});
					new Thread(new Runnable() {
						public void run() {
							synchronized(commentBox) {
								while (!commentBox.isReadyToClose()) {
									try {
										commentBox.wait();
									} catch (InterruptedException ie) {}
								}
							}
							SwingUtilities.invokeLater(new Runnable() {
								public void run() {
									panelSud.removeAll();
									panelSud.add(controles);
									panelSud.validate();
									ExplorateurVignettes.this.validate();
								}
							});
							commentBox = null;
						}
					}).start();
				}
			}
        });
        ajoutTag.addActionListener(new ActionListener() {
        	public void actionPerformed(ActionEvent ae) {
        		if (commentBox != null)
        			commentBox.close();
        		if (!list.isSelectionEmpty()) {
        			tagBox = new TagBox((PikImage) list.getSelectedValue());
        			SwingUtilities.invokeLater(new Runnable() {
						public void run() {
							panelSud.removeAll();
							panelSud.add(tagBox);
							panelSud.validate();
							ExplorateurVignettes.this.validate();
						}
					});
        			new Thread(new Runnable() {
        				public void run() {
        					synchronized(tagBox) {
								while (!tagBox.isReadyToClose()) {
									try {
										tagBox.wait();
									} catch (InterruptedException ie) {}
								}
							}
							SwingUtilities.invokeLater(new Runnable() {
								public void run() {
									panelSud.removeAll();
									panelSud.add(controles);
									panelSud.validate();
									ExplorateurVignettes.this.validate();
								}
							});
							tagBox = null;
        				}
        			}).start();
        		}
        	}
        });
        proprietes.addActionListener(new ActionListener() {
        	public void actionPerformed(ActionEvent ae) {
        		if (!list.isSelectionEmpty()) {
        			PikImage pik = (PikImage) list.getSelectedValue();
        			new ProprietesImageDialog(pik);
        		}
        	}
        });
        controles.add(affich);
        controles.add(fullScreen);
        controles.add(diaporama);
        controles.addSeparator();
        controles.add(proprietes);
        controles.addSeparator();
        controles.add(ajoutComment);
        controles.add(ajoutTag);
        controles.addSeparator();
        controles.add(suppr);
        panelSud.add(controles);

        scrollPane.setViewportView(list);
        add(recherche,BorderLayout.NORTH);
        add(scrollPane, BorderLayout.CENTER);
        add(panelSud, BorderLayout.SOUTH);
    }

    protected /*synchronized*/ void setAlbum(ImageContainer im) { album = im; }
    protected /*synchronized*/ void setListModel(PhotosListModel plm) { this.plm = plm; }
    protected /*synchronized*/ PhotosListModel getListModel() { return plm; }
    protected /*synchronized*/ void setProgressMonitor(ProgressMonitor pm) { progress = pm; }
    protected /*synchronized*/ ProgressMonitor getProgressMonitor() { return progress; }
    public synchronized boolean isChargementEnCours() { return chargementEnCours; }
    public synchronized void setChargementEnCours(boolean b) { chargementEnCours = b; }

    public void afficherAlbum(ImageContainer im) {
    	if (im != null && im != album) {
    		setChargementEnCours(false);
    		try {
    			semaphore.acquire();
    		} catch (InterruptedException ie) {
    			return;
    		}
//    		if (chargeur != null) {
//    			try {
//    				System.out.println("hello");
//    				chargeur.join();
//    			} catch (InterruptedException e) {
//    				e.printStackTrace();
//    				return;
//    			}
//    		}
    		setAlbum(im);
    		setListModel(new PhotosListModel(im,recherche.getSelectedComparator()));
    		list.setModel(plm);
    		recherche.setAlbumModel(plm);
    		list.repaint();
    		if (album.isEmpty()) { semaphore.release(); return; }



    		synchronized (this) {
    			setChargementEnCours(true);
    			chargeur = new Thread(new Runnable() {
    				public void run() {
    					int count = getAlbum().getImageCount();
    		    		String message = "Affiche le contenu "+((album instanceof Dossier)?"du dossier ":"de l'album ");
    		    		message += getAlbum().toString();

    		    		setProgressMonitor(new ProgressMonitor(pikasial.Pikasial.getFrame(),message,
    		    				"Veuillez patienter...", 0, count));
    					/* C'est super moche mais apparemment y'a pas moyen de faire autrement :s
    					 * sans faire encore plus moche */
    					final int[] i = {0};
    					java.util.Iterator<PikImage> it = getAlbum().getAllImages().iterator();
    					while (it.hasNext() && chargementEnCours && !progress.isCanceled()) {
    						final PikImage pikim = it.next();
    						try {
    							pikim.getVignette();
    							i[0]++;
    							getListModel().addImage(pikim);
    							getProgressMonitor().setProgress(i[0]);
//    							javax.swing.SwingUtilities.invokeLater(new Runnable() {
//    								public void run() {
//
//    									//progressMonitor.setNote(String.format("Terminé à %d%%.\n", i[0]));
//    								}
//    							});
    						} catch (IOException ioe) {
    							JOptionPane.showMessageDialog(ExplorateurVignettes.this,
    									"Erreur lors du chargement de la vignette !", "Erreur !",
    									JOptionPane.ERROR_MESSAGE);
    						}
    					}
    					try {
    						javax.swing.SwingUtilities.invokeLater(new Runnable() {
    							public void run() {
    								progress.close();
    							}
    						});
    					} catch (Exception e) { e.printStackTrace(); }
						semaphore.release();
    					//progressMonitor.setProgress(100);
    				}
    			});
    			chargeur.setPriority(Thread.MAX_PRIORITY-1);
    		}
    		chargeur.start();

//    		chargeur = null;
    	}
    }

    public boolean isSelectionEmpty() {
    	return list.isSelectionEmpty();
    }

    public void supprimerImages(PikImage[] images) {
        for (int i = 0; i < images.length; i++) {
            album.removeImage(images[i]);
            plm.removeImage(images[i]);
        }
    }

    public PikImage getSelectedVignette() {
    	return (PikImage) list.getSelectedValue();
    }

    public PikImage[] getSelectedVignettes() {
    	Object[] values = list.getSelectedValues();
    	PikImage[] ret = new PikImage[values.length];
    	for (int i=0; i<ret.length; i++) {
    		ret[i] = (PikImage) values[i];
    	}
    	return ret;
    }

    public void setSelectedVignette(PikImage pik) {
    	list.setSelectedValue(pik, true);
    }

    /**
     * Vide la liste des vignettes.
     */
    public void viderListe() {
        album = null;
        list.setModel(new PhotosListModel(album));
    }

    /**
     * Retourne le modèle de cet onglet, l'album observé.
     * @return l'album observé par cet onglet
     */
    public synchronized ImageContainer getAlbum() {
        return album;
    }

    /**
     * Sélectionne toutes les images dans la JList.
     */
    void selectAll() {
        int taille = list.getModel().getSize();
        int indices[] = new int[taille];
        for (int i = 0; i < taille; i++) {
            indices[i] = i;
        }
        list.setSelectedIndices(indices);
    }

    /**
     * Inverse la sélection de la JList.
     */
    void inverserSelection() {
        int taille = list.getModel().getSize();
        for (int i = 0; i < taille; i++) {
            if (!list.isSelectedIndex(i)) {
                list.addSelectionInterval(i, i);
            } else {
                list.removeSelectionInterval(i, i);
            }
        }
    }

    /**
     * Efface la selection de la JList.
     */
    void effacerSelection() {
        list.clearSelection();
    }

    /**
     * Retourne le nom de l'album observé par cet onglet.
     * @return le nom de l'album observé
     */
    public String getAlbumName() {
        if (album instanceof Dossier) {
            return ((Dossier) album).getName();
        } else {
            return ((AlbumPhotos) album).getName();
        }
    }

	public void update(Observable o, Object arg) {
		if (o == ListeAlbums.getInstance() && (arg instanceof ImageContainer)) {
			afficherAlbum((ImageContainer) arg);
		}
	}

	public void valueChanged(ListSelectionEvent e) {
		if (commentBox != null) {
			commentBox.close();
		}
		if (tagBox != null) {
			tagBox.close();
		}
		if (list.isSelectionEmpty()) {
			fullScreen.setEnabled(false);
			proprietes.setEnabled(false);
			ajoutComment.setEnabled(false);
			affich.setEnabled(false);
			ajoutTag.setEnabled(false);
			suppr.setEnabled(false);
		} else {
			fullScreen.setEnabled(true);
			proprietes.setEnabled(true);
			ajoutComment.setEnabled(true);
			affich.setEnabled(true);
			ajoutTag.setEnabled(true);
			suppr.setEnabled(true);
		}
	}

}

/**
 * Le décorateur de la liste de vignettes.
 *
 * @author ESIAL - Groupe 14
 */
@SuppressWarnings("serial")
final class ImageRenderer extends DefaultListCellRenderer {

    /** Décalage entre la taille de la cellule et celle de l'image. */
    private static final int TAILLE_DECALAGE = 40;
    /** Longueur maximum d'un nom affiché sans troncage. */
    private static final int LONGUEUR_MAX_NOM = 25;
    /** Longueur des caractères supplémentaires affichés lors d'un troncage. */
    private static final int LONGUEUR_SUPP_AFFICHE = 3;

    /**
     * Retourne le composant qui a été configuré pour afficher la valeur
     * spécifiée.
     *
     * @param list - la JList à décorer
     * @param value - l'objet retourné par list.getModel().getElementAt(index).
     * @param index - l'indice de la cellule
     * @param isSelected - vrai si la cellule est sélectionnée
     * @param cellHasFocus - vrai si elle a le focus.
     *
     * @return un composant qui affiche la valeur specifiée
     */
    @Override
    public Component getListCellRendererComponent(final JList list,
        final Object value,
        final int index,
        final boolean isSelected,
        final boolean cellHasFocus) {

        /* Comportement par défaut */
        Component c = super.getListCellRendererComponent(list, value,
            index, isSelected, cellHasFocus);
        JLabel label = (JLabel) c;
        label.setPreferredSize(
            new Dimension(PikImage.THUMB_WIDTH + TAILLE_DECALAGE,
            PikImage.THUMB_HEIGHT + TAILLE_DECALAGE));
        label.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
        label.setVerticalTextPosition(SwingConstants.BOTTOM);
        label.setHorizontalTextPosition(SwingConstants.CENTER);
        try {
            label.setIcon(((PikImage) value).getVignetteIcon());
        } catch (IOException ioe) {
            JOptionPane.showMessageDialog(null, ioe.getMessage() + "Pas cool!", "Erreur !",
                JOptionPane.ERROR_MESSAGE);
            return c;
        }
        String text = ((PikImage) value).getName();
        if (isSelected) {
            label.setBorder(BorderFactory.createLineBorder(Color.BLACK));
        }
        if (text.length() > LONGUEUR_MAX_NOM + LONGUEUR_SUPP_AFFICHE) {
            text = text.substring(0, LONGUEUR_MAX_NOM).concat("...");
        }

        label.setText(text);

        return label;
    }
}

